/*
 * UAE - The Un*x Amiga Emulator
 *
 * bsdsocket.library emulation
 *
 * Copyright 1997,98 Mathias Ortmann
 *
 */

#pragma once

#if BSDSOCKET_DEBUG_DEF > 0
    #define BSDTRACE(x) do { Logger::Write x; } while (0)
#else
    #define BSDTRACE(x)
#endif

extern int init_socket_layer();
extern void deinit_socket_layer();

/* inital size of per-process descriptor table (currently fixed) */
#define DEFAULT_DTABLE_SIZE 64

#define SCRATCHBUFSIZE 128

#define MAXPENDINGASYNC 512

#define MAXADDRLEN 256

#ifdef _WIN32
    #define SOCKET_TYPE SOCKET
#else
    #define SOCKET_TYPE int
#endif

/* allocated and maintained on a per-task basis */
struct socketbase
{
    struct socketbase* next;
    struct socketbase* nextsig; /* queue for tasks to signal */

    int dosignal;       /* signal flag */
    uint ownertask;      /* task that opened the library */
    int signal;         /* signal allocated for that task */
    int sb_errno, sb_herrno;    /* errno and herrno variables */
    uint errnoptr, herrnoptr;    /* pointers */
    uint errnosize, herrnosize;  /* pinter sizes */
    int dtablesize;     /* current descriptor/flag etc. table size */
    SOCKET_TYPE* dtable;    /* socket descriptor table */
    int* ftable;        /* socket flags */
    int resultval;
    uint hostent;        /* pointer to the current hostent structure (Amiga mem) */
    uint hostentsize;
    uint protoent;       /* pointer to the current protoent structure (Amiga mem) */
    uint protoentsize;
    uint servent;        /* pointer to the current servent structure (Amiga mem) */
    uint serventsize;
    uint sigstosend;
    uint eventsigs;      /* EVENT sigmask */
    uint eintrsigs;      /* EINTR sigmask */
    int eintr;          /* interrupted by eintrsigs? */
    int eventindex;     /* current socket looked at by GetSocketEvents() to prevent starvation */

    /* host-specific fields below */
    #ifdef _WIN32
    SOCKET_TYPE sockAbort;  /* for aborting WinSock2 select() (damn Microsoft) */
    SOCKET_TYPE sockAsync;  /* for aborting WSBAsyncSelect() in window message handler */
    int needAbort;      /* abort flag */
    void* hAsyncTask;       /* async task handle */
    void* hEvent;       /* thread event handle */
    uint* mtable;   /* window messages allocated for asynchronous event notification */
    #else
    uae_sem_t sem;      /* semaphore to notify the socket thread of work */
    uae_thread_id thread;   /* socket thread */
    int sockabort[2];       /* pipe used to tell the thread to abort a select */
    int action;
    int s;          /* for accept */
    uint name;       /* For gethostbyname */
    uint a_addr;     /* gethostbyaddr, accept */
    uint a_addrlen;      /* for gethostbyaddr, accept */
    uint flags;
    void* buf;
    uint len;
    uint to, tolen, from, fromlen;
    int nfds;
    uint sets[3];
    uint timeout;
    uint sigmp;
    #endif
};

#define LIBRARY_SIZEOF 36

struct UAEBSDBase
{
    byte dummy[LIBRARY_SIZEOF];
    struct socketbase* sb;
    byte scratchbuf[SCRATCHBUFSIZE];
};

/* socket flags */
/* socket events to report */
#define REP_ACCEPT 0x01     /* there is a connection to accept() */
#define REP_CONNECT 0x02    /* connect() completed */
#define REP_OOB 0x04        /* socket has out-of-band data */
#define REP_READ 0x08       /* socket is readable */
#define REP_WRITE 0x10      /* socket is writeable */
#define REP_ERROR 0x20      /* asynchronous error on socket */
#define REP_CLOSE 0x40      /* connection closed (graceful or not) */
#define REP_ALL 0x7f
/* socket events that occurred */
#define SET_ACCEPT 0x0100   /* there is a connection to accept() */
#define SET_CONNECT 0x0200  /* connect() completed */
#define SET_OOB 0x0400      /* socket has out-of-band data */
#define SET_READ 0x0800     /* socket is readable */
#define SET_WRITE 0x1000    /* socket is writeable */
#define SET_ERROR 0x2000    /* asynchronous error on socket */
#define SET_CLOSE 0x4000    /* connection closed (graceful or not) */
#define SET_ALL 0x7f00
/* socket properties */
#define SF_BLOCKING 0x80000000
#define SF_BLOCKINGINPROGRESS 0x40000000

uint addstr(uint* dst, const TCHAR* src);
uint addstr_ansi(uint* dst, const char* src);
uint strncpyha(uint dst, const char* src, int size);
uint addmem(uint* dst, const char* src, int len);

#define SB struct socketbase* sb

extern void bsdsocklib_seterrno(SB, int);
extern void bsdsocklib_setherrno(SB, int);

extern void sockmsg(uint, WPARAM, LPARAM);
extern void sockabort(SB);

extern void addtosigqueue(SB, int);
extern void removefromsigqueue(SB);
extern void sigsockettasks();
extern void locksigqueue();
extern void unlocksigqueue();

extern BOOL checksd(SB, int sd);
extern void setsd(SB, int, SOCKET_TYPE);
extern int getsd(SB, SOCKET_TYPE);
extern SOCKET_TYPE getsock(SB, int);
extern void releasesock(SB, int);

extern void waitsig(TrapContext * context, SB);
extern void cancelsig(TrapContext * context, SB);

extern int host_sbinit(TrapContext *, SB);
extern void host_sbcleanup(SB);
extern void host_sbreset();
extern void host_closesocketquick(SOCKET_TYPE);

extern int host_dup2socket(SB, int, int);
extern int host_socket(SB, int, int, int);
extern uint host_bind(SB, uint, uint, uint);
extern uint host_listen(SB, uint, uint);
extern void host_accept(TrapContext *, SB, uint, uint, uint);
extern void host_sendto(TrapContext *, SB, uint, uint, uint, uint, uint, uint);
extern void host_recvfrom(TrapContext *, SB, uint, uint, uint, uint, uint, uint);
extern uint host_shutdown(SB, uint, uint);
extern void host_setsockopt(SB, uint, uint, uint, uint, uint);
extern uint host_getsockopt(SB, uint, uint, uint, uint, uint);
extern uint host_getsockname(SB, uint, uint, uint);
extern uint host_getpeername(SB, uint, uint, uint);
extern uint host_IoctlSocket(TrapContext *, SB, uint, uint, uint);
extern uint host_shutdown(SB, uint, uint);
extern int host_CloseSocket(TrapContext *, SB, int);
extern void host_connect(TrapContext *, SB, uint, uint, uint);
extern void host_WaitSelect(TrapContext *, SB, uint, uint, uint, uint, uint, uint);
extern uint host_SetSocketSignals();
extern uint host_getdtablesize();
extern uint host_ObtainSocket();
extern uint host_ReleaseSocket();
extern uint host_ReleaseCopyOfSocket();
extern uint host_Inet_NtoA(TrapContext * context, SB, uint);
extern uint host_inet_addr(uint);
extern uint host_Inet_LnaOf();
extern uint host_Inet_NetOf();
extern uint host_Inet_MakeAddr();
extern uint host_inet_network();
extern void host_gethostbynameaddr(TrapContext *, SB, uint, uint, long);
extern uint host_getnetbyname();
extern uint host_getnetbyaddr();
extern void host_getservbynameport(TrapContext *, SB, uint, uint, uint);
extern void host_getprotobyname(TrapContext *, SB, uint);
extern void host_getprotobynumber(TrapContext *, SB, uint);
extern uint host_vsyslog();
extern uint host_Dup2Socket();
extern uint host_gethostname(uint, uint);

extern uae_ptr bsdlib_startup(uae_ptr);
extern void bsdlib_install();
extern void bsdlib_reset();

void bdslib_free();